home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Camelot / Camelot 084 (1990-10)(Swedish User Group of Amiga)(SE)(PD)[WB].zip / Camelot 084 (1990-10)(Swedish User Group of Amiga)(SE)(PD)[WB].adf / MakeC / iff_stuff.c < prev    next >
C/C++ Source or Header  |  1990-09-20  |  9KB  |  265 lines

  1.  
  2. /*
  3.     These are some IFF file handler routines...
  4. */
  5.  
  6. #ifndef IFF_H
  7.     #include "iff.h"
  8. #endif
  9.  
  10. UBYTE iff_disk_buffer[4096];   /* a 4K disk buffer to speed I/O to file  */
  11. SHORT iff_buffer_size;            /*  these are not used at the moment     */
  12. SHORT iff_buffer_position;        /*  but I figure they may come in handy  */
  13. ULONG iff_file_position;        /*  sometime.  Only 6 bytes, no biggie   */
  14.  
  15.  
  16.  
  17. /*
  18.     PullID() is done here as an actual subroutine, although it could just
  19.     as easily be set up as a macro with a #define.  All it does is takes
  20.     a pointer to a text buffer and yanks out the first four bytes and
  21.     shifts them into a ULONG, then returns it.
  22. */
  23.  
  24. ULONG PullID(what)
  25. UBYTE *what;
  26. {
  27.     return (ULONG)((ULONG)what[0]<<24 | (ULONG)what[1]<<16 | (ULONG)what[2]<<8 | (ULONG)what[3]);
  28. }
  29.  
  30.  
  31. /*
  32.     GetBMHD() takes a FILE pointer to an IFF file, and a pointer to a 
  33.     BitMapHeader.  It then searches the IFF file for the header and reads
  34.     the information into the BitMapHeader, one field at a time.  This 
  35.     coud be made considerably faster and simpler by doing a memcpy() from
  36.     the disk buffer instead, but this way makes it more clear what is in
  37.     the BitMapHeader and the relative positions within the file, so I'll
  38.     leave it like it is.
  39. */
  40.     
  41. BOOL GetBMHD(ifffile,header)
  42. FILE *ifffile;
  43. BitMapHeader *header;
  44. {
  45.     Chunk bmhdchunk;
  46.     BOOL error;
  47.                                         /* first find the chunk */
  48.     error=FindChunk(ifffile,MakeID('B','M','H','D'),&bmhdchunk);
  49.     if(error)
  50.         return TRUE;                    /* read the data into header */
  51.     header->w = ((UWORD)(bmhdchunk.ckdata[0]) << 8) | (bmhdchunk.ckdata[1]);
  52.     header->h = ((UWORD)(bmhdchunk.ckdata[2]) << 8) | (bmhdchunk.ckdata[3]);
  53.     header->x = ((WORD)(bmhdchunk.ckdata[4]) << 8) | (bmhdchunk.ckdata[5]);
  54.     header->y = ((WORD)(bmhdchunk.ckdata[6]) << 8) | (bmhdchunk.ckdata[7]);
  55.     header->nplanes = bmhdchunk.ckdata[8];
  56.     header->masking = bmhdchunk.ckdata[9];
  57.     header->compression = bmhdchunk.ckdata[10];
  58.     header->pad1 = 0;                    /* set to 0 and skip over a byte */
  59.     header->TransparentColor = (UWORD)(bmhdchunk.ckdata[12] << 8) | (bmhdchunk.ckdata[13]);
  60.     header->xAspect = bmhdchunk.ckdata[14];
  61.     header->yAspect = bmhdchunk.ckdata[15];
  62.     header->pageWidth = ((WORD)(bmhdchunk.ckdata[16]) << 8) | (bmhdchunk.ckdata[17]);
  63.     header->pageHeight = ((WORD)(bmhdchunk.ckdata[18]) << 8) | (bmhdchunk.ckdata[19]);
  64.     FreeMem(bmhdchunk.ckdata,bmhdchunk.cksize);        /* free memory */
  65.     return FALSE;
  66. }
  67.  
  68. /* 
  69.     GetViewModes() looks for a CAMG chunk in the IFF file.  If it finds
  70.     one, it stores the ViewModes word into the NewScreen structure.  If
  71.     there isn't, it sets up the minimal assumptions necessary to open the
  72.     screen properly (i.e. lace or not and hires or not).
  73. */
  74.  
  75. BOOL GetViewModes(newscreen,ifffile)
  76. struct NewScreen *newscreen;
  77. FILE *ifffile;
  78. {
  79.     BOOL error = FALSE;
  80.     Chunk camgchunk;
  81.     
  82.     error = FindChunk(ifffile,MakeID('C','A','M','G'),&camgchunk);
  83.     if(!error)
  84.         {
  85.             newscreen->ViewModes = PullID(camgchunk.ckdata) & CAMGMASK;
  86.             FreeMem(camgchunk.ckdata,camgchunk.cksize);
  87.         }
  88.     if(newscreen->Width > 384)            /* if no CAMG chunk, make it up */
  89.         newscreen->ViewModes |= HIRES;    /* if there was one, this won't */
  90.     if(newscreen->Height > 200)            /* hurt anything to double-check */
  91.         newscreen->ViewModes |= LACE;
  92.     return FALSE;    
  93. }
  94.  
  95. /*
  96.     FindChunk searches an IFF file for a chunk of type chunktype.  It 
  97.     makes use of the iff_disk_buffer for speedier I/O.  The buffer 
  98.     could be diddled with a little to improve speed, but you might wind
  99.     up with overkill on the reads (probably already a lot of that at 4K).
  100.     If it finds the chunk, it allocates memory for the chunk body 
  101.     UNLESS it is a BODY type chunk.  It then reads the data into the 
  102.     chunkdata section and returns.  It is up to the caller to free the 
  103.     allocated memory.  If it is looking for a BODY type chunk, rather than
  104.     allocate memory for the body, it leaves this part up to the caller
  105.     (useful for on-the-fly decompression), and instead positions the 
  106.     IFF file pointer so that it points to the start of the BODY chunk data.
  107. */
  108.  
  109. BOOL FindChunk(ifffile,chunktype,chunk)
  110. FILE *ifffile;
  111. ULONG chunktype;
  112. Chunk *chunk;
  113. {
  114.     SHORT temppos;
  115.     BOOL foundchunk= FALSE;
  116.     ULONG bytes_read=0,seek_spot=0;
  117.     SHORT buffer_size=0;
  118.     
  119.     rewind(ifffile);                /* start at top of file  */
  120.     buffer_size = fread(iff_disk_buffer,1,4096,ifffile);    /* fill buffer */
  121.     while(TRUE)        /* search whole file for chunk */
  122.         {
  123.             for(temppos=0;temppos<buffer_size;temppos++)    /* scan buffer */
  124.                 if(PullID(&iff_disk_buffer[temppos]) == chunktype)
  125.                     {
  126.                         foundchunk = TRUE;    /* found chunk type ? */
  127.                         break;
  128.                     }
  129.             if((foundchunk) || feof(ifffile))    /* done ? */
  130.                 break;
  131.             buffer_size = fread(iff_disk_buffer,1,4096,ifffile);
  132.             bytes_read += buffer_size;        /* how far are we into file? */
  133.         };    
  134.     seek_spot = bytes_read + temppos + 8;    /* for a BODY chunk */
  135.     if(foundchunk)    
  136.         {
  137.             chunk->ckID = PullID(&iff_disk_buffer[temppos]);
  138.             chunk->cksize = PullID(&iff_disk_buffer[temppos+4]);
  139.             if(chunk->ckID == MakeID('B','O','D','Y'))
  140.                 {
  141.                     chunk->ckdata = NULL;        /* fix file pointer */
  142.                     fseek(ifffile,seek_spot,SEEK_SET);
  143.                     return FALSE;                /* I'm outta here... */
  144.                 }
  145.             chunk->ckdata = (UBYTE *)AllocMem(chunk->cksize,MEMF_CLEAR);
  146.             if(chunk->ckdata == NULL)    /* not a BODY chunk at this point */
  147.                 {
  148.                     printf("\nNo memory for chunk!!\n");
  149.                     return TRUE;
  150.                 }
  151.             temppos += 8;    /* read the data into the chunkdata section */
  152.             for(bytes_read=0;bytes_read<chunk->cksize;bytes_read++)
  153.                 chunk->ckdata[bytes_read] = iff_disk_buffer[temppos++];
  154.         }    
  155.     else
  156.         return TRUE;    /* hey, somethin' ain't right */
  157.     return FALSE;        /* everything's fine */
  158. }
  159.  
  160. /*
  161.     GetColorMap scans an IFF file for a colormap, loading it into the
  162.     colortable given.  It returns the number of colors in the table.
  163. */
  164.  
  165. SHORT GetColorMap(ifffile,colortable)
  166. FILE *ifffile;
  167. UWORD *colortable;
  168. {
  169.     Chunk cmapchunk;
  170.     SHORT count=0;
  171.     BOOL error = FALSE;
  172.     UWORD red,green,blue;
  173.  
  174.     error = FindChunk(ifffile,MakeID('C','M','A','P'),&cmapchunk);
  175.     if(!error)                                /* found colormap? */
  176.         {                                    /* make RGB4's out of it */
  177.             for(;count<cmapchunk.cksize/3;count++)
  178.                 {
  179.                     red = cmapchunk.ckdata[(count*3)] >> 4;        /* use high order 4 bits */
  180.                     green = cmapchunk.ckdata[(count*3)+1] >> 4;
  181.                     blue = cmapchunk.ckdata[(count*3)+2] >> 4;
  182.                     colortable[count]  = blue;
  183.                     colortable[count] |= green << 4;
  184.                     colortable[count] |= red << 8;
  185.                 }
  186.             FreeMem(cmapchunk.ckdata,cmapchunk.cksize);
  187.         }
  188.     return (count);
  189. }
  190.  
  191.  
  192.  
  193. /*
  194.     ReadPic() is the picture reader.  It takes a pointer to a bitmap, a
  195.     pointer to a file which need not be at any particular position, (it
  196.     will find the data with FindChunk()), and a pointer to a BitMapHeader
  197.     describing the picture being read.
  198.     It doesn't matter whether the picture is on or off screen or whether
  199.     it is not the same size as the bitmap.  If it is too small, it is read
  200.     anyway.  If it is too large, it is clipped at the BitMap boundaries.
  201.     Compressed and masked images are handled correctly.
  202. */
  203.  
  204. BOOL ReadPic(bitmap,ifffile,header)
  205. struct BitMap *bitmap;
  206. FILE *ifffile;
  207. BitMapHeader *header;
  208. {
  209.     BOOL error = FALSE;
  210.     BOOL mask = FALSE;
  211.     BOOL compress = FALSE;
  212.     Chunk bodychunk;
  213.     SHORT scanline,plane,count,needed,read;
  214.     BYTE data,run;
  215.     UBYTE bit_bucket[255];
  216.     UBYTE *dest;
  217.     
  218.     if(header->masking == mskHasMask)
  219.         mask = TRUE;                    /* got a mask on it ?*/
  220.     if(header->compression == cmpByteRun1)
  221.         compress = TRUE;                /* compressed via ByteRun1? */
  222.     needed = header->w/8;                /* how many BYTES do we need? */
  223.     if(header->w%8)                        /* if odd number of pixels, */
  224.         needed++;                        /* adjust that number */
  225.     error = FindChunk(ifffile,MakeID('B','O','D','Y'),&bodychunk);
  226.     if(error)
  227.         return TRUE;                    /* YIKES!  No Body! */
  228.     for(scanline=0;scanline<header->h;scanline++)    /* lines first */
  229.         for(plane=0;plane<header->nplanes;plane++)    /* then planes */
  230.             {
  231.                 if(mask & scanline%2)            /* ignore mask */
  232.                     dest = bit_bucket;            /* toss mask planes */
  233.                 else                        /* figure scanline in bitmap */
  234.                     dest = bitmap->Planes[plane]+(scanline*bitmap->BytesPerRow);
  235.                 if(!compress)                /* not too likely, but easy */
  236.                     for(count=0;count<needed;count++)
  237.                         *dest++ = fgetc(ifffile);
  238.                 else                        /* image is compressed */
  239.                     {
  240.                         count=0;            /* count is bytes decompressed */
  241.                         while(count<needed)    
  242.                             {
  243.                                 run = fgetc(ifffile);    /* size of run */
  244.                                 if(run>=0)                /* literal run */
  245.                                     {
  246.                                         count += run+1;
  247.                                         for(read=0;read<=run;read++)
  248.                                             *dest++ = fgetc(ifffile);
  249.                                     }
  250.                                 else if (run != 128)    /* repeat run */
  251.                                     {
  252.                                         run = run*(-1);
  253.                                         count += run+1;
  254.                                         data = fgetc(ifffile);
  255.                                         for(read=0;read<=run;read++)
  256.                                             *dest++ = data;
  257.                                     }
  258.                             }
  259.                     }
  260.         }
  261.     return FALSE;
  262. }
  263.  
  264.  
  265.